﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class A
{
public:
	virtual ~A()
	{
		cout << "~A()" << endl;
	}
};
class B : public A {
public:
	~B()
	{
		cout << "~B()->delete:" << _p << endl;
		delete _p;

		//这里也解释了一个问题：
		//直接在子类中直接调用 ~A（）函数是无法调用的，需要指明作用域A::~A() 
		//因为子类和父类的析构函数函数名本质是一样的，构成隐藏关系
	    //而它们的析构函数名被处理成同一的destructor也是为了解决像下面的场景

	}
protected:
	int* _p = new int[10];
};
// 只有派⽣类的析构函数重写了父类的析构函数，下⾯的delete对象调⽤析构函数，才能
// 构成多态，才能保证p1和p2指向的对象正确的调⽤析构函数。
int main()
{
	//有下列这样的场景：delete p1没问题，但是 delete p2 ,究竟是调用A类的析构函数还是调用
	//                 B类的析构函数 ？由于“切断”可知，调用的是A类的析构函数，因此就会
	//                 造成内存泄漏。

	//基于这样的场景，就需要用到多态

	A* p1 = new A;
	A* p2 = new B;

	//delete的本质：调用析构函数destructor  +  operator delete 
	delete p1;
	delete p2;
	
		return 0;
}
//具体原理：
//基类的析构函数为虚函数，此时派⽣类析构函数只要定义，⽆论是否加virtual关键字，都与基类的析
//构函数构成重写，虽然基类与派⽣类析构函数名字不同看起来不符合重写的规则，实际上编译器对析
//构函数的名称做了特殊处理，编译后析构函数的名称统⼀处理成destructor，所以基类的析构函数加了
//virtual修饰，派⽣类的析构函数就构成重写。

//上⾯的代码我们可以看到，如果~A()，不加virtual，那么delete p2时只调⽤的A的析构函数，没有调⽤
//B的析构函数，就会导致内存泄漏问题，因为~B()中在释放资源。
 
//注意：这个问题⾯试中经常考察，要结合类似下⾯的样例才能讲清楚，为什么基类中的析构
//函数建议设计为虚函数。